#ifndef _creazy_matrix_
#define _creazy_matrix_


#include <iostream>
#include <stdlib.h>
#include <iomanip>
using namespace std;

template <typename T>
class Matrix
{
protected:
  int n_row, n_col;
  T *matrix_element;

public:
  Matrix(){
	matrix_element = NULL;
	n_row = 0;
	n_col = 0;
  }

  
  Matrix(int nrows, int ncols){
	if(nrows<0||ncols<0)
	  {
		cerr<<"[err] error col's number or row's number!2\n";
		exit(-1);
	  }
	n_row = nrows;
	n_col = nrows;
	allocMem();
	for(int i =0; i<n_col*n_row; i++)
	  *(matrix_element+i) = 0;
  }

  Matrix(int nrows, int ncols, T Arr[],int arrsize){
	if(nrows<0||ncols<0)
	  {
		cerr<<"[err] error col's number or row's number!1\n";
		exit(-1);
	  }
	n_row = nrows;
	n_col = nrows;
	allocMem();
	for(int i =0; i<n_col*n_row; i++)
	  *(matrix_element+i) = 0;

	for(int i =0; i<n_col*n_row; i++)
	  *(matrix_element+i) = Arr[i];
  }
  
  ~Matrix(){
	releaseMem();
  }
	
  void allocMem(){ // 初始化矩阵
	matrix_element = new T[n_row * n_col];
  }
  void releaseMem(){
	if(matrix_element){delete[]matrix_element; matrix_element = NULL;}
  }
  
  void exitAbnormal(int _err_code) const;

  bool is_square(){return (this->n_row == this->n_col);}


  Matrix<T>& operator=(const Matrix<T>& _Matrix){
	this->n_row=_Matrix.n_row;
	this->n_col=_Matrix.n_col;
	allocMem();
	int n = n_row*n_col;
	for(int i = 0; i<n; i++)
	  *(this->matrix_element+i) =*( _Matrix.matrix_element+i);
  }
 
  
  T& operator()(int _i, int _j)const{
	if(_j<0||_i<0||n_row<_i||n_col<_j)
	  { cerr<<"[err] error col's number or row's number!3\n";
	  exit(-1);
	  }//exitAbnormal(2);
	return matrix_element[_i*n_col+_j];
  }

  
  Matrix<T> operator*( const Matrix<T>& r){
	if(this->n_col != r.n_row)
	  {cerr<<"[err] error col's number or row's number!5\n";
   	  exit(-1);
	  }
	//exitAbnormal(1);
	if(this->n_col<=0||this->n_row<=0){cerr<<"[err] error col's number or row's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);

	Matrix<T> temp;
	temp.n_row = this->n_row;
	temp.n_col = r.n_col;
	temp.allocMem();
	for (int i = 0; i<temp.n_row;i++){
	  for(int j = 0; j<temp.n_col;j++){
		T sum = 0;
		for(int k =0; k<n_col; k++){
		  sum += *(this->matrix_element+i*n_col+k)*(*(r.matrix_element+k*r.n_col+j));
		}
		temp(i,j) = sum;
	  }
	}
	return temp;	
  }  


	int getn_row()const{return this->n_row;}
	int getn_col()const{return this->n_col;}
 
  void show_matrix(){
	for(int i = 0; i<this->getn_row();i++){
		for(int j =0; j<this->getn_col(); j++)
		  cout<<setw(5)<< *(this->matrix_element+i*this->getn_col()+j);
		cout<<endl;
  	}
	cout<<endl;
  }
};

template <typename T> 
class ColVector;

template <typename T> 
class RowVector : public Matrix<T>
{
protected:
  int n_row=1;
  
 public:
  RowVector()
	{
	  Matrix<T>::matrix_element = NULL;
	  Matrix<T>::n_col =0;
	}

  RowVector(int ncols){
	if(ncols<0)
	  {
		cerr<<"[err] error col's number!2\n";
		exit(-1);
	  }
	Matrix<T>::n_col = ncols;
	allocMem();
	for(int i = 0; i<Matrix<T>::n_col; i++)
	  *(Matrix<T>::matrix_element+i) = 0;
  }

  RowVector( int ncols, T Arr[]){
	if(ncols<0)
	  {
		cerr<<"[err] error col's number!1\n";
		exit(-1);
	  }
	Matrix<T>::n_col = ncols;
	allocMem();
	for(int i =0; i<Matrix<T>::n_col; i++)
	  *(Matrix<T>::matrix_element+i) = 0;

	for(int i =0; i<Matrix<T>::n_col; i++)
	  *(Matrix<T>::matrix_element+i) = Arr[i];
  }


  
  ~RowVector() {releaseMem();}

  void allocMem(){
	Matrix<T>::matrix_element = new T[Matrix<T>::n_col];
  }
  void releaseMem(){
	if(Matrix<T>::matrix_element){delete[]Matrix<T>::matrix_element; Matrix<T>::matrix_element = NULL;}
  }

  RowVector<T>& operator=(const RowVector<T>& _RowVector){
	this->n_col=_RowVector.n_col;
	this->allocMem();
	for(int i = 0; i<this->n_col; i++)
	  {*(this->matrix_element+i) =*(_RowVector.matrix_element+i);}
  }

  
  T operator*( const RowVector<T>& r){
	if(Matrix<T>::n_col != r.n_col)
	  {cerr<<"[err] error col's number!5\n";
   	  exit(-1);
	  }
	//exitAbnormal(1);
	if(Matrix<T>::n_col<=0){cerr<<"[err] error col's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);

	T temp = 0;
	for (int i = 0; i<Matrix<T>::n_col;i++){
	  temp += *(Matrix<T>::matrix_element+i)*(*(r.matrix_element+i));
		}
	return temp;	
  }


  RowVector<T> operator*( const Matrix<T>& r){
	if(Matrix<T>::n_col != r.getn_row())
	  {cerr<<"[err] error col's number!5\n";
  	  exit(-1);
	  }
	//exitAbnormal(1);
	if(Matrix<T>::n_col<=0){cerr<<"[err] error col's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);

	RowVector<T> temp;
	temp.n_col = r.getn_col();
	temp.allocMem();
	for (int i = 0; i<temp.n_col;i++){
	  T sum =0;
	  for(int j =0; j<Matrix<T>::n_col;j++){
		sum += *(Matrix<T>::matrix_element+j)*(r(j,i));
		}
	  *(temp.matrix_element+i) = sum;
	  }
	return temp;	
 } 

  int getn_col()const{return Matrix<T>::n_col;}
  int getn_row()const{return this->n_row;}
  T get_matrix_element(int i)const{
	if(i<0||i> Matrix<T>::n_col) {
		cout<<"error input"<<endl;	
		exit(-1);
	}	
	return *(Matrix<T>::matrix_element+i);
	}
 
  void show_matrix(){
	for(int j =0; j<this->getn_col(); j++)
		cout<<setw(5)<< *(Matrix<T>::matrix_element+j);
	cout<<endl<<endl;
  }
   
T operator*(const ColVector<T> &r){
	if((this->n_row != 1)||r.getn_col()!=1)
	  {cerr<<"[err] error col's number or row's number!5\n";
   	  exit(-1);
	  }
	//exitAbnormal(1);
	if(this->n_col<=0||r.getn_row()<=0||this->n_col!=r.getn_row()){cerr<<"[err] error col's number or row's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);
	T sum = 0;
	for(int j = 0; j<this->n_col;j++){
		sum +=*(this->matrix_element+j)*(r.get_matrix_element(j));
	}
	return sum;	
	} 

};


template <typename T> 
class ColVector : public Matrix<T>
{
protected:
  int n_col=1;
  
 public:
  ColVector()
	{
	  Matrix<T>::matrix_element = NULL;
	  Matrix<T>::n_row =0;
	}

  ColVector(int nrows){
	if(nrows<0)
	  {
		cerr<<"[err] error row's number!2\n";
		exit(-1);
	  }
	Matrix<T>::n_row = nrows;
	allocMem();
	for(int i = 0; i<Matrix<T>::n_row; i++)
	  *(Matrix<T>::matrix_element+i) = 0;
  }

  ColVector( int nrows, T Arr[]){
	if(nrows<0)
	  {
		cerr<<"[err] error row's number!1\n";
		exit(-1);
	  }
	Matrix<T>::n_row = nrows;
	allocMem();
	for(int i =0; i<Matrix<T>::n_row; i++)
	  *(Matrix<T>::matrix_element+i) = 0;

	for(int i =0; i<Matrix<T>::n_row; i++)
	  *(Matrix<T>::matrix_element+i) = Arr[i];
  }


  
  ~ColVector() {releaseMem();}

  void allocMem(){
	Matrix<T>::matrix_element = new T[Matrix<T>::n_row];
  }
  void releaseMem(){
	if(Matrix<T>::matrix_element){delete[]Matrix<T>::matrix_element; Matrix<T>::matrix_element = NULL;}
  }

  ColVector<T>& operator=(const ColVector<T>& _ColVector){
	this->n_row=_ColVector.n_row;
	this->allocMem();
	for(int i = 0; i<this->n_row; i++)
	  {*(this->matrix_element+i) =*(_ColVector.matrix_element+i);}
  }

  
  T operator*( const ColVector<T>& r){
	if(Matrix<T>::n_row != r.n_row)
	  {cerr<<"[err] error row's number!5\n";
   	  exit(-1);
	  }
	//exitAbnormal(1);
	if(Matrix<T>::n_row<=0){cerr<<"[err] error row's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);

	T temp = 0;
	for (int i = 0; i<Matrix<T>::n_row;i++){
	  temp += *(Matrix<T>::matrix_element+i)*(*(r.matrix_element+i));
		}
	return temp;	
  }


  ColVector<T> operator*( const Matrix<T>& l){
	if(Matrix<T>::n_row != l.getn_col())
	  {cerr<<"[err] error row's number!5\n";
  	  exit(-1);
	  }
	//exitAbnormal(1);
	if(Matrix<T>::n_row<=0){cerr<<"[err] error row's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);

	ColVector<T> temp;
	temp.n_row = l.getn_row();
	temp.allocMem();
	for (int i = 0; i<temp.n_row;i++){
	  T sum =0;
	  for(int j =0; j<Matrix<T>::n_row;j++){
		sum += l(i,j)*(*(Matrix<T>::matrix_element+j));
		}
	  *(temp.matrix_element+i) = sum;
	  }
	return temp;
	}	

  Matrix<T> operator*(const RowVector<T> &r){
	if((this->n_col != 1)||r.getn_row()!=1)
	  {cerr<<"[err] error col's number or row's number!5\n";
   	  exit(-1);
	  }
	//exitAbnormal(1);
	if(this->n_row<=0||r.getn_col()<=0||r.getn_col()!=this->n_row){cerr<<"[err] error col's number or row's number!6\n";
	  exit(-1);}
	// exitAbnormal(2);

	Matrix<T> temp(this->n_row,r.getn_col());
	for (int i = 0; i<temp.getn_row();i++){
	  for(int j = 0; j<temp.getn_col();j++){
		temp(i,j) =*(this->matrix_element+i)*(r.get_matrix_element(j));
	  }
	}
	return temp;	
	} 

  int getn_row()const{return Matrix<T>::n_row;}
  int getn_col()const{return this->n_col;}
  T get_matrix_element(int i)const{
	if(i<0||i> Matrix<T>::n_row) {
		cout<<"error input"<<endl;	
		exit(-1);
	}	
	return *(Matrix<T>::matrix_element+i);
	}
 
  void show_matrix(){
	for(int j =0; j<this->getn_row(); j++)
		cout<<setw(5)<< *(Matrix<T>::matrix_element+j)<<endl;
	cout<<endl;
  }
 
 
};




#else
//do nothing.
#endif
  
